package MetaClassifierAlgorithms;

import Definitions.GraphClass;
import Global.ConstantVariable;
import Global.GlobalClass;
import Result.ResultClass;
import Sampling.SamplingAbstractClass;
import Utility.WorkerUtilityClass;

public class DegreeFilteredMetaClassifier extends MetaClassifierAbstractClass {

	DegreeFilteredMetaClassifier(String metaClassifierName, GraphClass graph,
			GlobalClass global, SamplingAbstractClass currentSampling, double[][][] probabilityDistributionMatrixForTheClassifiers) {
		
		super(metaClassifierName, graph, global, currentSampling, probabilityDistributionMatrixForTheClassifiers);
		// TODO Auto-generated constructor stub
	}
	/*
	public void metaClassify()
	{		
		double maximumAccuracyObtained = 0;
		ResultClass result=null;
		double accuracyObtained;		
		
		double[] degreeLevels = graph.getPropertiesOfTheGraphWithRespectToEdgeType().get(ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE).degreeDistributionRelatedProps.getDegreeLevels();
		
		double maximumAccurateDegreeLevel=degreeLevels[0];		
		
		for(int i=0; i<degreeLevels.length; i++)
		{
			metaClassifyForTheGivenDegree(degreeLevels[i]);
			result = new ResultClass(null);
			result.setSampling(currentSampling);			

			result.getEvaluationResult().createConfMatAndPrepareTheResults();
			
			accuracyObtained = result.getEvaluationResult().getMeasures().getAccuracy();
			
			System.out.println("Degree:"+degreeLevels[i]+" accuracyObtained:"+accuracyObtained);
			
			if(accuracyObtained>maximumAccuracyObtained)
			{
				maximumAccuracyObtained = accuracyObtained;
				maximumAccurateDegreeLevel = degreeLevels[i];				
			}			
		}
		
		System.out.println("maximumAccurateDegreeLevel:"+maximumAccurateDegreeLevel+" maximumAccuracyObtained:"+maximumAccuracyObtained);
		metaClassifyForTheGivenDegree(maximumAccurateDegreeLevel);		
	}
	

	void metaClassifyForTheGivenDegree(double degree)
	{
		double metaResultProbabilitiesPerClassBasis[];
		int metaClassLabelEstimated;
	
		double[] degreeListOfNodes = graph.getPropertiesOfTheGraphWithRespectToEdgeType().get(ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE).degreeDistributionRelatedProps.getDegreeListOfNodes();
		
		for(int nodeNo=0; nodeNo<probabilityDistributionMatrixForTheClassifiers[0].length; nodeNo++)
		{
			
			if(degreeListOfNodes[currentSampling.getTestNodes().get(nodeNo).getOrder()]<=degree)
				metaResultProbabilitiesPerClassBasis = probabilityDistributionMatrixForTheClassifiers[0][nodeNo];
			else
				metaResultProbabilitiesPerClassBasis = probabilityDistributionMatrixForTheClassifiers[1][nodeNo];
			
			metaClassLabelEstimated = WorkerUtilityClass.findMaxIndexForTheGivenVector(metaResultProbabilitiesPerClassBasis);
			
			currentSampling.setClassLabelEstimated(currentSampling.getTestNodes().get(nodeNo), metaClassLabelEstimated);			
			
		}		
	}*/
	
	public void metaClassify()
	{
		double maximumAccuracyObtained = 0;
		ResultClass result=null;
		double accuracyObtained;
		
				
		double[] degreeLevels = graph.getPropertiesOfTheGraphWithRespectToEdgeType().get(ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE).degreeDistributionRelatedProps.getDegreeLevels();
		
		double maximumAccurateDegreeLevel=degreeLevels[0];		
		
		for(int i=0; i<degreeLevels.length; i++)
		{
			metaClassifyForTheGivenDegree(degreeLevels[i]);
			result = new ResultClass(null);
			result.setSampling(currentSampling);			

			result.getEvaluationResult().createConfMatAndPrepareTheResults();
			
			accuracyObtained = result.getEvaluationResult().getMeasures().getAccuracy();
			
			System.out.println("Degree:"+degreeLevels[i]+" accuracyObtained:"+accuracyObtained);
			
			if(accuracyObtained>maximumAccuracyObtained)
			{
				maximumAccuracyObtained = accuracyObtained;
				maximumAccurateDegreeLevel = degreeLevels[i];				
			}			
		}
		
		System.out.println("maximumAccurateDegreeLevel:"+maximumAccurateDegreeLevel+" maximumAccuracyObtained:"+maximumAccuracyObtained);
		metaClassifyForTheGivenDegree(maximumAccurateDegreeLevel);		

		
	}
	
	void metaClassifyForTheGivenDegree(double degree)
	{
		double metaResultProbabilitiesPerClassBasis[];
		int metaClassLabelEstimated;
	
		for(int nodeNo=0; nodeNo<probabilityDistributionMatrixForTheClassifiers[0].length; nodeNo++)
		{
			
			if(selectWhichOneToUseContentOrLink(nodeNo) == ConstantVariable.Common_ConstantVariables.USE_LINK_GRAPH)
				metaResultProbabilitiesPerClassBasis = probabilityDistributionMatrixForTheClassifiers[0][nodeNo];
			else
				metaResultProbabilitiesPerClassBasis = probabilityDistributionMatrixForTheClassifiers[1][nodeNo];
			
			metaClassLabelEstimated = WorkerUtilityClass.findMaxIndexForTheGivenVector(metaResultProbabilitiesPerClassBasis);
			
			currentSampling.setClassLabelEstimated(currentSampling.getTestNodes().get(nodeNo), metaClassLabelEstimated);			
			
		}
	}
	
	int selectWhichOneToUseContentOrLink(int nodeNo)
	{
		double[] accuracyLevelsForLink = graph.getPropertiesOfTheGraphWithRespectToEdgeType().get(ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE).accuracyRelatedProps.getAccuracyVsDegreeDistribution();
		double[] accuracyLevelsForContent = graph.getPropertiesOfTheGraphWithRespectToEdgeType().get(ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE_FOR_CONTENT_GRAPH).accuracyRelatedProps.getAccuracyVsDegreeDistribution();
		
		double[] degreeLevelsForLink = graph.getPropertiesOfTheGraphWithRespectToEdgeType().get(ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE).degreeDistributionRelatedProps.getOrginalDegreeLevels();
		double[] degreeLevelsForContent = graph.getPropertiesOfTheGraphWithRespectToEdgeType().get(ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE_FOR_CONTENT_GRAPH).degreeDistributionRelatedProps.getOrginalDegreeLevels();
		
		double[] degreeListOfNodesForLink = graph.getPropertiesOfTheGraphWithRespectToEdgeType().get(ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE).degreeDistributionRelatedProps.getDegreeListOfNodes();
		double[] degreeListOfNodesForContent = graph.getPropertiesOfTheGraphWithRespectToEdgeType().get(ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE_FOR_CONTENT_GRAPH).degreeDistributionRelatedProps.getDegreeListOfNodes();
		
		int isClassifierSureAndIfItIsWhichOne = checkIfAClassifierIsMoreSureAboutItsResult(nodeNo);
		
		if(isClassifierSureAndIfItIsWhichOne!=ConstantVariable.Common_ConstantVariables.USE_NONE)
			return isClassifierSureAndIfItIsWhichOne;
		
		if(degreeListOfNodesForLink[nodeNo]==0 && degreeListOfNodesForContent[nodeNo]>=0)
			return ConstantVariable.Common_ConstantVariables.USE_CONTENT_GRAPH;
		else if(degreeListOfNodesForContent[nodeNo]==0 && degreeListOfNodesForLink[nodeNo]>0)
			return ConstantVariable.Common_ConstantVariables.USE_LINK_GRAPH;

		double accuracyWrtDegreeLevelForLink = accuracyLevelsForLink[WorkerUtilityClass.findIndexForTheGivenElementInTheVector(degreeLevelsForLink, degreeListOfNodesForLink[nodeNo])];
		double accuracyWrtDegreeLevelForContent = accuracyLevelsForContent[WorkerUtilityClass.findIndexForTheGivenElementInTheVector(degreeLevelsForContent, degreeListOfNodesForContent[nodeNo])];
		
		if(accuracyWrtDegreeLevelForLink >= accuracyWrtDegreeLevelForContent)
			return ConstantVariable.Common_ConstantVariables.USE_LINK_GRAPH;
		else
			return ConstantVariable.Common_ConstantVariables.USE_CONTENT_GRAPH;
			
	}
	
	int checkIfAClassifierIsMoreSureAboutItsResult(int nodeNo)
	{
		double[] classifierMaxProbDistResultsForTheNode;
		int numberOfClassifiers;
		double firstMaxValueOfTheClassifiers = WorkerUtilityClass.findMaxForTheGivenVector(probabilityDistributionMatrixForTheClassifiers[0][nodeNo]);
		double secondMaxValueOfTheClassifiers = WorkerUtilityClass.findMaxForTheGivenVector(probabilityDistributionMatrixForTheClassifiers[1][nodeNo]);;
		double temp;
		int selectedClsIndex = 0;
		
		if(secondMaxValueOfTheClassifiers > firstMaxValueOfTheClassifiers)
		{
			temp = firstMaxValueOfTheClassifiers;
			firstMaxValueOfTheClassifiers = secondMaxValueOfTheClassifiers;
			secondMaxValueOfTheClassifiers = temp;	
			selectedClsIndex = 1;
		}	
		
		numberOfClassifiers = probabilityDistributionMatrixForTheClassifiers.length;
		
		classifierMaxProbDistResultsForTheNode = new double[numberOfClassifiers];
		
		for(int i=2; i<numberOfClassifiers; i++)
		{
			classifierMaxProbDistResultsForTheNode[i] = WorkerUtilityClass.findMaxForTheGivenVector(probabilityDistributionMatrixForTheClassifiers[i][nodeNo]);
			
			if(firstMaxValueOfTheClassifiers < classifierMaxProbDistResultsForTheNode[i])
			{
				secondMaxValueOfTheClassifiers = firstMaxValueOfTheClassifiers;
				firstMaxValueOfTheClassifiers = classifierMaxProbDistResultsForTheNode[i];
				selectedClsIndex = i;				
			}
			else if(secondMaxValueOfTheClassifiers < classifierMaxProbDistResultsForTheNode[i])
			{
				secondMaxValueOfTheClassifiers = classifierMaxProbDistResultsForTheNode[i];			
			}
		}
		
		
		if(firstMaxValueOfTheClassifiers > secondMaxValueOfTheClassifiers*1.15)
		{
			if(selectedClsIndex == 0)
				return ConstantVariable.Common_ConstantVariables.USE_LINK_GRAPH;
			else
				return ConstantVariable.Common_ConstantVariables.USE_CONTENT_GRAPH;			
		}
		else
			return ConstantVariable.Common_ConstantVariables.USE_NONE;			
	}
}
